package com.qingzhuge.member.wx;

import cn.binarywang.wx.miniapp.api.WxMaService;
import cn.binarywang.wx.miniapp.api.WxMaUserService;
import cn.binarywang.wx.miniapp.bean.WxMaJscode2SessionResult;
import cn.binarywang.wx.miniapp.bean.WxMaPhoneNumberInfo;
import cn.binarywang.wx.miniapp.util.crypt.WxMaCryptUtils;
import cn.binarywang.wx.miniapp.util.json.WxMaGsonBuilder;
import com.qingzhuge.common.enums.ESexType;
import com.qingzhuge.exception.LoginException;
import com.qingzhuge.exception.ValidatorException;
import com.qingzhuge.member.entity.SysMember;
import com.qingzhuge.member.entity.SysMemberAvatar;
import com.qingzhuge.member.entity.SysMemberThirdPartyAuth;
import com.qingzhuge.member.entity.SysThirdAppConfig;
import com.qingzhuge.member.dto.UserLoginRequest;
import com.qingzhuge.member.dto.UserLoginResponse;
import com.qingzhuge.member.dto.WxUserInfoRequestDto;
import com.qingzhuge.member.dto.WxUserPhoneInfoResponse;
import com.qingzhuge.member.dto.response.SysMemberDto;
import com.qingzhuge.member.enums.EnumThirdOauthType;
import com.qingzhuge.member.service.ISysMemberService;
import com.qingzhuge.member.service.ISysMemberThirdOauthService;
import com.qingzhuge.member.service.ISysThirdAppConfigService;
import com.qingzhuge.member.service.wx.IWxUserService;
import me.chanjar.weixin.common.error.WxErrorException;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;

/**
 * @author : zero.xiao
 * @description :
 * @date : 2018/10/17 0017 上午 11:03
 * @modified :
 * @since :
 */
@Service
public class WxUserServiceImpl implements IWxUserService {
    private static final Logger log = LoggerFactory.getLogger(WxUserServiceImpl.class);
    @Resource
    private ISysThirdAppConfigService thirdAppConfigService;
    @Resource
    private ISysMemberService memberService;
    @Resource
    private ISysMemberThirdOauthService memberThirdOauthService;


    @Override
    public UserLoginResponse login(String appid, WxUserInfoRequestDto request, EnumThirdOauthType type) {
        WxMaService wxMaService = getWxMaService(appid, request);

        try {
            WxMaUserService userService = wxMaService.getUserService();
            WxMaJscode2SessionResult session = userService.getSessionInfo(request.getCode());

            log.debug("weixin login Result:{}",session);
            //解析数据
            SysMemberThirdPartyAuth oauth = info(appid, session.getSessionKey(), request);
            //通过小程序openid查找
            SysMemberThirdPartyAuth thirdOauth = memberThirdOauthService.findByOpenId(oauth.getOpenId());
            if (null == thirdOauth){
                thirdOauth = memberThirdOauthService.obj2obj(oauth,SysMemberThirdPartyAuth.class);
                thirdOauth.setType(oauth.getType());
            }
            thirdOauth.setType(type);

            UserLoginResponse response = new UserLoginResponse();
            Long userId = thirdOauth.getUserId();
            SysMember user = memberService.findById(userId);
            boolean bindMobile = true;
            //如果系统没有用户
            if (null == user ){
                UserLoginRequest loginRequest = request.getLoginRequest();
                if (null != loginRequest && StringUtils.isNotEmpty(loginRequest.getMobile())) {
                    //通过手机号登录
                    response = memberService.mobileLogin(loginRequest, response);
                    SysMemberDto userInfo = response.getUserInfo();
                    user = memberService.dto2Bean(userInfo);
                    //如果用户没有设置昵称，则把设置微信的昵称
                    if (StringUtils.isEmpty(user.getNickname())) {
                        user.setNickname(thirdOauth.getNickName());
                    }
                    //如果用户没有设置性别
                    if (null == user.getSex()) {
                        if (1 == thirdOauth.getGender()) {
                            user.setSex(ESexType.male);
                        } else if (2 == thirdOauth.getGender()) {
                            user.setSex(ESexType.female);
                        } else {
                            user.setSex(ESexType.unknown);
                        }
                    }
                    //如果用户没有设置头像
                    SysMemberAvatar avatar = user.getAvatar();
                    if (null == avatar) {
                        avatar = new SysMemberAvatar();
                        avatar.setUrlWx(oauth.getAvatarUrl());
                        user.setAvatar(avatar);
                    }else{
                        avatar.setUrlWx(oauth.getAvatarUrl());
                    }
                    if (null == user.getRegisterType()) {
                        user.setRegisterType(oauth.getType());
                    }
                    user.setLoginType(oauth.getType());
                    user = memberService.save(user);
                    thirdOauth.setUserId(user.getId());
                    memberThirdOauthService.save(thirdOauth);
                }else{
                    bindMobile = false;
                }
            }else {
                thirdOauth.setUserId(user.getId());
            }
            response = memberThirdOauthService.login(thirdOauth);
            response.setBindMobile(bindMobile);
            return response;
        } catch (WxErrorException e) {
            log.error(e.getMessage(), e);
            return new UserLoginResponse(e.getError().getErrorCode(),e.getError().getErrorMsg());
        }
    }

    private SysMemberThirdPartyAuth info(String appid, String sessionKey, WxUserInfoRequestDto request) {
        WxMaService wxMaService = getWxMaService(appid, request);
        if (!wxMaService.getUserService().checkUserInfo(sessionKey, request.getRawData(), request.getSignature())) {
            throw new ValidatorException("user check failed");
        }
        // 解密用户信息
        String json = WxMaCryptUtils.decrypt(sessionKey, request.getEncryptedData(), request.getIv());
        SysMemberThirdPartyAuth userInfo = WxMaGsonBuilder.create().fromJson(json, SysMemberThirdPartyAuth.class);
        log.debug("wx user info :{}",userInfo);
        return userInfo;
    }

    @Override
    public WxUserPhoneInfoResponse phone(String appid, String sessionKey, WxUserInfoRequestDto request) {
        WxMaService wxMaService = getWxMaService(appid, request);
        // 解密
        WxMaPhoneNumberInfo phoneNoInfo = wxMaService.getUserService().getPhoneNoInfo(sessionKey, request.getEncryptedData(), request.getIv());
        WxUserPhoneInfoResponse response = new WxUserPhoneInfoResponse();
        response.setCountryCode(phoneNoInfo.getCountryCode());
        response.setPhoneNumber(phoneNoInfo.getPhoneNumber());
        response.setPurePhoneNumber(phoneNoInfo.getPurePhoneNumber());
        WxUserPhoneInfoResponse.Watermark watermark = new WxUserPhoneInfoResponse.Watermark();
        watermark.setAppid(phoneNoInfo.getWatermark().getAppid());
        watermark.setTimestamp(phoneNoInfo.getWatermark().getTimestamp());
        response.setWatermark(watermark);

        return response;
    }

    private WxMaService getWxMaService(String appid, WxUserInfoRequestDto request) {
        if (StringUtils.isEmpty(appid) || null == request || StringUtils.isEmpty(request.getCode())) {
            throw new LoginException("empty data");
        }
        SysThirdAppConfig thirdAppConfig = thirdAppConfigService.findByAppId(appid);
        if(null == thirdAppConfig){
            throw new ValidatorException("服务配置错误");
        }
        WxMaConfigurationUtil configurationUtil = WxMaConfigurationUtil.build();
        // 用户信息校验
        return configurationUtil.getWxMaService(thirdAppConfig);
    }

    @Override
    public SysMember updateMobile(String appid, WxUserInfoRequestDto request, Long uid){
        WxMaService wxMaService = getWxMaService(appid, request);

        try {
            WxMaUserService userService = wxMaService.getUserService();
            WxMaJscode2SessionResult session = userService.getSessionInfo(request.getCode());
            WxUserPhoneInfoResponse phone = phone(appid, session.getSessionKey(), request);
            return memberThirdOauthService.updateMobile(uid,phone.getPhoneNumber());
        } catch (WxErrorException e) {
            log.error(e.getMessage(), e);
            return null;
        }
    }
}
